import { VEEdge, VEFace, VEHeader, VEType, VEVertex} from "./index";
import { frontSide } from "../utils";

const _u = new BABYLON.Vector3();
const _v = new BABYLON.Vector3();

export class VELoop {

  /**
   * 通用状态记录
   */
  public header: VEHeader;

  public vertex: VEVertex;

  public edge: VEEdge | null = null;

  public face: VEFace | null = null;

  declare next: VELoop;
  declare prev: VELoop;
  declare pair: VELoop;

  /**
   * uv值记录于loop数据，与vertex数据分开，vertex不需要考虑冗余问题，转换为babylon mesh时按需动态添加冗余点；
   * TODO: 多通道UV处理可以寻找更简洁的记录方式；
   */
  public uv: number[] = [0, 0];
  
  declare uv2: number[];
  declare uv3: number[];
  declare uv4: number[];
  declare uv5: number[];
  declare uv6: number[];

  get id() {
    return this.vertex.index + '-' + this.pair!.vertex.index;
  }

  /**
   * 边凹凸情况判断；
   * true：凸边；false：凹边或pair为null；
   */
  get isConcave() {
    if (this.pair) {
      return frontSide(
        this.vertex.position,
        this.next.vertex.position,
        this.prev.vertex.position,
        this.pair.prev.vertex.position) > 0;
    }
    return false;
  }

  public constructor(v: VEVertex) {
    this.header = new VEHeader(VEType.Loop);

    this.vertex = v;

  }

  /**
   * 无归属面片的半边，不确定结构是否完整
   */
  public isFree() {
    return this.face === null;
  }

  /**
   * 结构完整的边界
   */
  public isBoundary() {
    return this.face === null && this.pair !== null && this.pair.face !== null;
  }

  public *nextLoop() {
    const start: VELoop = this;
    let curr: VELoop | null = start;
    do {
      yield curr;
      curr = curr!.next;
    } while (curr !== start);
    return null;
  }

  public *prevLoop() {
    const start: VELoop = this;
    let curr: VELoop | null = start;
    do {
      yield curr;
      curr = curr!.next;
    } while (curr !== start);
    return null;
  }


  public containsPoint(point: BABYLON.Vector3, tolerance = 1e-10): boolean {
    if (this.vertex && this.next) {
      _u.copyFrom(this.vertex.position.subtract(point));
      _v.copyFrom(this.next.vertex.position.subtract(point));
      return BABYLON.Vector3.Distance(_u, point) < tolerance
    } else {
      return false;
    }

  }
}